package com.group9.handinhand.service;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.group9.handinhand.dao.TagDao;
import com.group9.handinhand.dao.model.CommunityTag;
import com.group9.handinhand.dao.model.EventTag;
import com.group9.handinhand.dao.model.OfferTag;
import com.group9.handinhand.dao.model.RequestTag;
import com.group9.handinhand.dao.model.Tag;
import com.group9.handinhand.dao.model.UserTag;
import com.group9.handinhand.service.so.CommunitySO;
import com.group9.handinhand.service.so.CommunityTagSO;
import com.group9.handinhand.service.so.EventSO;
import com.group9.handinhand.service.so.EventTagSO;
import com.group9.handinhand.service.so.OfferSO;
import com.group9.handinhand.service.so.OfferTagSO;
import com.group9.handinhand.service.so.RequestSO;
import com.group9.handinhand.service.so.RequestTagSO;
import com.group9.handinhand.service.so.TagSO;
import com.group9.handinhand.service.so.UserSO;
import com.group9.handinhand.service.so.UserTagSO;

@Transactional
@Service("tagService")
public class TagServiceImpl implements TagService {
	
	static final Logger logger = LoggerFactory.getLogger(TagService.class);
	
	@Autowired 
	TagDao tagDao = new TagDao();
	
	@Override
	public TagSO getTagById(Long tagId) {
		Tag model = tagDao.findTagById(tagId);
		if(model != null)
			return model.convertToServiceObject();
		return null;
	}
	@Override
	public TagSO getTagByName(String tagName) {
		Tag model = tagDao.findTagByName(tagName);
		if(model != null)
			return model.convertToServiceObject();
		return null;
	}
	@Override
	public void saveTag(TagSO tag) {
		tagDao.saveTag(tag.convertToModelObject());
	}
	@Override
	public List<TagSO> getAllTags(){
		List<Tag> modelList = tagDao.findAllTags();
		List<TagSO> soList = new ArrayList<TagSO>();
		for (Tag tag : modelList) {
			soList.add(tag.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public void saveUserTags(UserSO user, List<String> selectedTags) {
		List<UserTagSO> oldUserTags = getUserTagsByUser(user);
		for (String tagName : selectedTags) {
			if(tagName != null) {
				TagSO tag = getTagByName(tagName);
				if(tag == null){
					TagSO newTag = new TagSO();
					newTag.setTagName(tagName);
					saveTag(newTag);
					tag = getTagByName(tagName);
				}
				if(tag != null) {
					UserTagSO userTag = getUserTagByTagAndUser(tag, user);
					if(userTag == null){
						userTag = new UserTagSO();
						userTag.setTag(tag);
						userTag.setUser(user);
						saveUserTag(userTag);
					}
					if(oldUserTags.contains(userTag))
						oldUserTags.remove(userTag);
				}
			}
		}
		for (UserTagSO userTagSO : oldUserTags) {
			deleteUserTag(userTagSO);
		}
	}
	
	@Override
	public void deleteUserTag(UserTagSO userTagSO) {
		tagDao.deleteUserTag(userTagSO.convertToModelObject());
	}
	
	@Override
	public void saveUserTag(UserTagSO userTag) {
		tagDao.saveUserTag(userTag.convertToModelObject());
	}
	
	@Override
	public List<UserTagSO> getUserTagsByUser(UserSO userSO) {
		List<UserTag> modelList = tagDao.findUserTagsByUser(userSO.convertToModelObject());
		List<UserTagSO> soList = new ArrayList<UserTagSO>();
		for (UserTag model : modelList) {
			soList.add(model.convertToServiceObject());
		}
		return soList;
	}
	
	@Override
	public UserTagSO getUserTagByTagAndUser(TagSO tagSO, UserSO userSO) {
		UserTag userTag = tagDao.findUserTagByTagIdandUserId(tagSO.convertToModelObject(), userSO.convertToModelObject());
		if (userTag != null) 
			return userTag.convertToServiceObject();
		return null;
	}

	@Override
	public List<TagSO> getTagsByRelatedUserId(long userId) {
		List<Tag> modelList = tagDao.findTagsByRelatedUserId(userId);
		List<TagSO> soList = new ArrayList<TagSO>();
		for (Tag tag : modelList) {
			soList.add(tag.convertToServiceObject());
		}
		return soList;
	}
	
	
	@Override
	public void saveCommunityTags(CommunitySO community, List<String> selectedTags) {
		List<CommunityTagSO> oldCommunityTags = getCommunityTagsByCommunity(community);
		for (String tagName : selectedTags) {
			if(tagName != null) {
				TagSO tag = getTagByName(tagName);
				if(tag == null){
					TagSO newTag = new TagSO();
					newTag.setTagName(tagName);
					saveTag(newTag);
					tag = getTagByName(tagName);
				}
				if(tag != null) {
					CommunityTagSO communityTag = getCommunityTagByTagAndCommunity(tag, community);
					if(communityTag == null){
						communityTag = new CommunityTagSO();
						communityTag.setTag(tag);
						communityTag.setCommunity(community);
						saveCommunityTag(communityTag);
					}
					if(oldCommunityTags.contains(communityTag))
						oldCommunityTags.remove(communityTag);
				}
			}
		}
		for (CommunityTagSO communityTagSO : oldCommunityTags) {
			deleteCommunityTag(communityTagSO);
		}
		
	}
	@Override
	public List<TagSO> getTagsByRelatedCommunityId(long communityId) {
		List<Tag> modelList = tagDao.findTagsByRelatedCommunityId(communityId);
		List<TagSO> soList = new ArrayList<TagSO>();
		for (Tag tag : modelList) {
			soList.add(tag.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public CommunityTagSO getCommunityTagByTagAndCommunity(TagSO tagSO,	CommunitySO communitySO) {
		CommunityTag communityTag = tagDao.findCommunityTagByTagIdandCommunityId(tagSO.convertToModelObject(), communitySO.convertToModelObject());
		if (communityTag != null) 
			return communityTag.convertToServiceObject();
		return null;
	}
	@Override
	public void saveCommunityTag(CommunityTagSO communityTag) {
		tagDao.saveCommunityTag(communityTag.convertToModelObject());
		
	}
	@Override
	public List<CommunityTagSO> getCommunityTagsByCommunity(CommunitySO communitySO) {
		List<CommunityTag> modelList = tagDao.findCommunityTagsByCommunity(communitySO.convertToModelObject());
		List<CommunityTagSO> soList = new ArrayList<CommunityTagSO>();
		for (CommunityTag model : modelList) {
			soList.add(model.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public void deleteCommunityTag(CommunityTagSO communityTagSO) {
		tagDao.deleteCommunityTag(communityTagSO.convertToModelObject());	
	}
	@Override
	public void saveEventTags(EventSO event, List<String> selectedTags) {
		List<EventTagSO> oldEventTags = getEventTagsByEvent(event);
		for (String tagName : selectedTags) {
			if(tagName != null) {
				TagSO tag = getTagByName(tagName);
				if(tag == null){
					TagSO newTag = new TagSO();
					newTag.setTagName(tagName);
					saveTag(newTag);
					tag = getTagByName(tagName);
				}
				if(tag != null) {
					EventTagSO eventTag = getEventTagByTagAndEvent(tag, event);
					if(eventTag == null){
						eventTag = new EventTagSO();
						eventTag.setTag(tag);
						eventTag.setEvent(event);
						saveEventTag(eventTag);
					}
					if(oldEventTags.contains(eventTag))
						oldEventTags.remove(eventTag);
				}
			}
		}
		for (EventTagSO eventTagSO : oldEventTags) {
			deleteEventTag(eventTagSO);
		}
	}
	@Override
	public List<TagSO> getTagsByRelatedEventId(long eventId) {
		List<Tag> modelList = tagDao.findTagsByRelatedEventId(eventId);
		List<TagSO> soList = new ArrayList<TagSO>();
		for (Tag tag : modelList) {
			soList.add(tag.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public EventTagSO getEventTagByTagAndEvent(TagSO tagSO, EventSO eventSO) {
		EventTag eventTag = tagDao.findEventTagByTagIdandEventId(tagSO.convertToModelObject(), eventSO.convertToModelObject());
		if (eventTag != null) 
			return eventTag.convertToServiceObject();
		return null;
	}
	@Override
	public void saveEventTag(EventTagSO eventTag) {
		tagDao.saveEventTag(eventTag.convertToModelObject());
	}
	@Override
	public List<EventTagSO> getEventTagsByEvent(EventSO eventSO) {
		List<EventTag> modelList = tagDao.findEventTagsByCEvent(eventSO.convertToModelObject());
		List<EventTagSO> soList = new ArrayList<EventTagSO>();
		for (EventTag model : modelList) {
			soList.add(model.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public void deleteEventTag(EventTagSO eventTagSO) {
		tagDao.deleteEventTag(eventTagSO.convertToModelObject());			
	}

	@Override
	public void saveOfferTags(OfferSO offer, List<String> selectedTags) {
		List<OfferTagSO> oldOfferTags = getOfferTagsByOffer(offer);
		for (String tagName : selectedTags) {
			if(tagName != null) {
				TagSO tag = getTagByName(tagName);
				if(tag == null){
					TagSO newTag = new TagSO();
					newTag.setTagName(tagName);
					saveTag(newTag);
					tag = getTagByName(tagName);
				}
				if(tag != null) {
					OfferTagSO offerTag = getOfferTagByTagAndOffer(tag, offer);
					if(offerTag == null){
						offerTag = new OfferTagSO();
						offerTag.setTag(tag);
						offerTag.setOffer(offer);
						saveOfferTag(offerTag);
					}
					if(oldOfferTags.contains(offerTag))
						oldOfferTags.remove(offerTag);
				}
			}
		}
		for (OfferTagSO offerTagSO : oldOfferTags) {
			deleteOfferTag(offerTagSO);
		}
	}
	@Override
	public List<TagSO> getTagsByRelatedOfferId(long offerId) {
		List<Tag> modelList = tagDao.findTagsByRelatedOfferId(offerId);
		List<TagSO> soList = new ArrayList<TagSO>();
		for (Tag tag : modelList) {
			soList.add(tag.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public OfferTagSO getOfferTagByTagAndOffer(TagSO tagSO, OfferSO offerSO) {
		OfferTag offerTag = tagDao.findOfferTagByTagIdandOfferId(tagSO.convertToModelObject(), offerSO.convertToModelObject());
		if (offerTag != null) 
			return offerTag.convertToServiceObject();
		return null;
	}
	@Override
	public void saveOfferTag(OfferTagSO offerTag) {
		tagDao.saveOfferTag(offerTag.convertToModelObject());
	}
	@Override
	public List<OfferTagSO> getOfferTagsByOffer(OfferSO offerSO) {
		List<OfferTag> modelList = tagDao.findOfferTagsByCOffer(offerSO.convertToModelObject());
		List<OfferTagSO> soList = new ArrayList<OfferTagSO>();
		for (OfferTag model : modelList) {
			soList.add(model.convertToServiceObject());
		}
		return soList;
	}
	@Override
	public void deleteOfferTag(OfferTagSO offerTagSO) {
		tagDao.deleteOfferTag(offerTagSO.convertToModelObject());			
	}
	
	@Override
	public void saveRequestTags(RequestSO request, List<String> selectedTags) {
		List<RequestTagSO> oldRequestTags = getRequestTagsByRequest(request);
		for (String tagName : selectedTags) {
			if(tagName != null) {
				TagSO tag = getTagByName(tagName);
				if(tag == null){
					TagSO newTag = new TagSO();
					newTag.setTagName(tagName);
					saveTag(newTag);
					tag = getTagByName(tagName);
				}
				if(tag != null) {
					RequestTagSO requestTag = getRequestTagByTagAndRequest(tag, request);
					if(requestTag == null){
						requestTag = new RequestTagSO();
						requestTag.setTag(tag);
						requestTag.setRequest(request);
						saveRequestTag(requestTag);
					}
					if(oldRequestTags.contains(requestTag))
						oldRequestTags.remove(requestTag);
				}
			}
		}
		for (RequestTagSO requestTagSO : oldRequestTags) {
			deleteRequestTag(requestTagSO);
		}
	}
	
	@Override
	public void deleteRequestTag(RequestTagSO requestTagSO) {
		tagDao.deleteRequestTag(requestTagSO.convertToModelObject());
	}
	
	@Override
	public void saveRequestTag(RequestTagSO requestTag) {
		tagDao.saveRequestTag(requestTag.convertToModelObject());
	}
	
	@Override
	public List<RequestTagSO> getRequestTagsByRequest(RequestSO requestSO) {
		List<RequestTag> modelList = tagDao.findRequestTagsByRequest(requestSO.convertToModelObject());
		List<RequestTagSO> soList = new ArrayList<RequestTagSO>();
		for (RequestTag model : modelList) {
			soList.add(model.convertToServiceObject());
		}
		return soList;
	}
	
	@Override
	public RequestTagSO getRequestTagByTagAndRequest(TagSO tagSO, RequestSO requestSO) {
		RequestTag requestTag = tagDao.findRequestTagByTagIdandRequestId(tagSO.convertToModelObject(), requestSO.convertToModelObject());
		if (requestTag != null) 
			return requestTag.convertToServiceObject();
		return null;
	}

	@Override
	public List<TagSO> getTagsByRelatedRequestId(long requestId) {
		List<Tag> modelList = tagDao.findTagsByRelatedRequestId(requestId);
		List<TagSO> soList = new ArrayList<TagSO>();
		for (Tag tag : modelList) {
			soList.add(tag.convertToServiceObject());
		}
		return soList;
	}
	
}
